package org.zlpt.contract.dao;

import com.owlike.genson.Genson;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.contract.ContractInterface;
import org.hyperledger.fabric.contract.annotation.Contract;
import org.hyperledger.fabric.contract.annotation.Transaction;
import org.hyperledger.fabric.shim.ChaincodeException;
import org.hyperledger.fabric.shim.ChaincodeStub;
import org.zlpt.entity.co.AuthenticationCO;


@Contract(
        name = "authentication"
)
public final class AuthenticationContract implements ContractInterface {
    static final String AUTHENTICATION_COLLECTION_NAME = "authenticationCollection";
    private final Genson genson = new Genson();


    @Transaction(intent = Transaction.TYPE.EVALUATE)
    public boolean AuthenticationExists(final Context ctx, String authenticationJson){
        ChaincodeStub stub = ctx.getStub();
        AuthenticationCO authentication = genson.deserialize(authenticationJson, AuthenticationCO.class);

        String authenticationJSON = stub.getStringState(authentication.formKey());

        return (authenticationJSON != null && !authenticationJSON.isEmpty());
    }


    @Transaction(intent = Transaction.TYPE.SUBMIT)
    public AuthenticationCO CreateAuthentication(final Context ctx, String authenticationJson) {
        ChaincodeStub stub = ctx.getStub();

        if (AuthenticationExists(ctx, authenticationJson)) {
            String errorMessage = String.format("authentication already exists");
            System.out.println(errorMessage);
            throw new ChaincodeException(errorMessage);
        }

        verifyClientOrgMatchesPeerOrg(ctx);

        AuthenticationCO authentication = genson.deserialize(authenticationJson, AuthenticationCO.class);

        System.out.printf("CreateAuthentication Put: collection %s, ID %s\n", AUTHENTICATION_COLLECTION_NAME, authentication.formKey());

        stub.putPrivateData(AUTHENTICATION_COLLECTION_NAME, authentication.formKey(), authenticationJson);

        return authentication;
    }
    @Transaction(intent = Transaction.TYPE.EVALUATE)
    public AuthenticationCO ReadAuthentication(final Context ctx, String userId) {
        ChaincodeStub stub = ctx.getStub();

        verifyClientOrgMatchesPeerOrg(ctx);


        byte[] authenticationPrvJSON = stub.getPrivateData(AUTHENTICATION_COLLECTION_NAME, AuthenticationCO.formKey(Long.valueOf(userId)));

        if (authenticationPrvJSON == null || authenticationPrvJSON.length == 0 ){
            String errorMessage = String.format("Authentication %s is not exit", AuthenticationCO.formKey(Long.valueOf(userId)));
            System.err.println(errorMessage);
            throw new ChaincodeException(errorMessage);
        }

        AuthenticationCO authentication = genson.deserialize(authenticationPrvJSON, AuthenticationCO.class);

        return authentication;

    }
    @Transaction(intent = Transaction.TYPE.SUBMIT)
    public AuthenticationCO UpdateAuthentication(final Context ctx, String authenticationJson) {
        ChaincodeStub stub = ctx.getStub();

        AuthenticationCO authentication = genson.deserialize(authenticationJson, AuthenticationCO.class);

        if (!AuthenticationExists(ctx, authenticationJson)) {
            String errorMessage = String.format("authentication does not exist");
            System.out.println(errorMessage);
            throw new ChaincodeException(errorMessage);
        }

        byte[] oldAuthenticationPrvJSON = stub.getPrivateData(AUTHENTICATION_COLLECTION_NAME , authentication.formKey());

        AuthenticationCO oldauthentication = genson.deserialize(oldAuthenticationPrvJSON, AuthenticationCO.class);
        String sortedJson = genson.serialize(authentication);

        verifyClientOrgMatchesPeerOrg(ctx);

        stub.putPrivateData(AUTHENTICATION_COLLECTION_NAME,authentication.formKey(), sortedJson);
        return oldauthentication;
    }
    @Transaction(intent = Transaction.TYPE.SUBMIT)
    public void DeleteAuthentication(final Context ctx, String userId) {
        ChaincodeStub stub = ctx.getStub();

        byte[] authenticationPrvJSON = stub.getPrivateData(AUTHENTICATION_COLLECTION_NAME, AuthenticationCO.formKey(Long.valueOf(userId)));

        if (authenticationPrvJSON == null || authenticationPrvJSON.length == 0 ){
            String errorMessage = String.format("Authentication %s is not exit", AuthenticationCO.formKey(Long.valueOf(userId)));
            System.err.println(errorMessage);
            throw new ChaincodeException(errorMessage);
        }
        verifyClientOrgMatchesPeerOrg(ctx);

        System.out.printf("DeleteAuthentication: collection %s, ID %s\n", AUTHENTICATION_COLLECTION_NAME, AuthenticationCO.formKey(Long.valueOf(userId)));

        stub.delPrivateData(AUTHENTICATION_COLLECTION_NAME, AuthenticationCO.formKey(Long.valueOf(userId)));
    }

    private void verifyClientOrgMatchesPeerOrg(final Context ctx) {
        String clientMSPID = ctx.getClientIdentity().getMSPID();
        String peerMSPID = ctx.getStub().getMspId();

        if (!peerMSPID.equals(clientMSPID)) {
            String errorMessage = String.format("Client from org %s is not authorized to read or write private data from an org %s peer", clientMSPID, peerMSPID);
            System.err.println(errorMessage);
            throw new ChaincodeException(errorMessage);
        }
    }


}






